<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <title>Shell教程  &middot; sitename</title>
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1">


<meta name="description" content="Shell教程 description" />

<meta name="keywords" content="one, two, ">


<meta property="og:title" content="Shell教程  &middot; sitename ">
<meta property="og:site_name" content="sitename"/>
<meta property="og:url" content="https://lvzongcheng.gitee.io/linux/shell/" />
<meta property="og:locale" content="en-EN">


<meta property="og:type" content="article" />
<meta property="og:description" content="Shell教程 description"/>
<meta property="og:article:published_time" content="2017-05-13T00:00:00Z" />
<meta property="og:article:modified_time" content="2017-05-13T00:00:00Z" />

  
    
<meta property="og:article:tag" content="one">
    
<meta property="og:article:tag" content="two">
    
  

  

<script type="application/ld+json">
  {
    "@context": "http://schema.org",
    "@type": "Article",
    "headline": "Shell教程",
    "author": {
      "@type": "Person",
      "name": "LvZongCheng"
    },
    "datePublished": "2017-05-13",
    "description": "Shell教程 description",
    "wordCount":  4299 
  }
</script>



<link rel="canonical" href="https://lvzongcheng.gitee.io/linux/shell/" />

<link rel="apple-touch-icon-precomposed" sizes="144x144" href="https://lvzongcheng.gitee.io/touch-icon-144-precomposed.png">
<link href="https://lvzongcheng.gitee.io/favicon.png" rel="icon">

<meta name="generator" content="Hugo 0.60.0" />

  <!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->

<link href='https://fonts.googleapis.com/css?family=Merriweather:300%7CRaleway%7COpen+Sans' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="/css/font-awesome.min.css">
<link rel="stylesheet" href="/css/style.css">
<link rel="stylesheet" href="/css/highlight/default.css">

  
  
	<script>
	  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
	  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
	  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
	  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

	  ga('create', 'Your Google Analytics tracking code', 'auto');
	  ga('send', 'pageview');

	</script>

</head>
<body>
  <main id="main-wrapper" class="container main_wrapper has-sidebar">
    <header id="main-header" class="container main_header">
  <div class="container brand">
  <div class="container title h1-like">
  <a class="baselink" href="https://lvzongcheng.gitee.io">
  LvZongCheng

</a>

</div>

  
<div class="container topline">
  
  淡定 执著 进取 自律


</div>


</div>

  <nav class="container nav primary no-print">
  

<a class="homelink" href="https://lvzongcheng.gitee.io">home</a>


  
<a href="https://lvzongcheng.gitee.io/framework" title="Show list of Frameworks">Frameworks</a>

<a href="https://lvzongcheng.gitee.io/java" title="Show list of Java">Java</a>

<a href="https://lvzongcheng.gitee.io/linux" title="Show list of Linux">Linux</a>

<a href="https://lvzongcheng.gitee.io/redis" title="Show list of Redis">Redis</a>

<a href="https://lvzongcheng.gitee.io/sql" title="Show list of SQL">SQL</a>

<a href="https://lvzongcheng.gitee.io/Spring" title="Show list of Spring">Spring</a>

<a href="https://lvzongcheng.gitee.io/tools" title="Show list of Tools">Tools</a>

<a href="https://lvzongcheng.gitee.io/webpage" title="Show list of WebPage">WebPage</a>

<a href="https://lvzongcheng.gitee.io/information" title="Show list of information">information</a>

<a href="https://lvzongcheng.gitee.io/network" title="Show list of network">network</a>

<a href="https://lvzongcheng.gitee.io/%E5%BE%AE%E6%9C%8D%E5%8A%A1" title="Show list of 微服务">微服务</a>

<a href="https://lvzongcheng.gitee.io/%E6%80%BB%E7%BB%93" title="Show list of 总结">总结</a>

<a href="https://lvzongcheng.gitee.io/%E6%9C%BA%E5%99%A8%E8%87%AA%E5%8A%A8%E5%8C%96" title="Show list of 机器自动化">机器自动化</a>

<a href="https://lvzongcheng.gitee.io/%E6%B1%87%E7%BC%96" title="Show list of 汇编">汇编</a>

<a href="https://lvzongcheng.gitee.io/%E8%AE%B0%E4%BA%8B%E6%9C%AC" title="Show list of 记事本">记事本</a>


</nav>

<div class="container nav secondary no-print">
  
<a id="contact-link-email" class="contact_link" rel="me" aria-label="Email" href="mailto:Lyc19880405@163.com">
  <span class="fa fa-envelope-square"></span></a>



<a id="contact-link-github" class="contact_link" rel="me" aria-label="Github" href="https://github.com/enten/hugo-boilerplate">
  <span class="fa fa-github-square"></span></a>




 


















</div>


  

</header>


<article id="main-content" class="container main_content single">
  <header class="container hat">
  <h1>Shell教程
</h1>

</header>

  <div class="container content">
  <p><a href="http://c.biancheng.net/cpp/shell/">shell教程</a>  
<code>Shell在平常应用中，建议不要用 root 帐号运行 Shell</code></p>
<h6 id="toc">[TOC]</h6>
<h5 id="shell">Shell简介</h5>
<p>Shell本身是一个用C语言编写的程序，它是用户使用Unix/Linux的桥梁，用
户的大部分工作都是通过Shell完成的。Shell既是一种命令语言，又是一种
程序设计语言。作为命令语言，它交互式地解释和执行用户输入的命令；作
为程序设计语言，它定义了各种变量和参数，并提供了许多在高级语言中才
具有的控制结构，包括循环和分支。</p>
<h6 id="shell1">Shell有两种执行命令的方式：</h6>
<ul>
<li>交互式（Interactive）：解释执行用户的命令，用户输入一条命令，Shell就解释执行一条。</li>
<li>批处理（Batch）：用户事先写一个Shell脚本(Script)，其中有很多条命令，让Shell一次把这些命令执行完，而不必一条一条地敲命令。</li>
</ul>
<h5 id="shell2">几种常见的Shell</h5>
<p>Shell是一种脚本语言，那么，就必须有解释器来执行这些脚本。
Unix/Linux上常见的Shell脚本解释器有bash、sh、csh、ksh等，习惯上把它们称作一种Shell。我们常说有多少种Shell，其实说的是Shell脚本解释器。<br>
<strong>bash</strong>  
bash是Linux标准默认的shell，本教程也基于bash讲解。bash由Brian Fox和Chet Ramey共同完成，是BourneAgain Shell的缩写，内部命令一共有40个。<br>
Linux使用它作为默认的shell是因为它有诸如以下的特色：<br>
可以使用类似DOS下面的doskey的功能，用方向键查阅和快速输入并修改命令。<br>
自动通过查找匹配的方式给出以某字符串开头的命令。<br>
包含了自身的帮助功能，你只要在提示符下面键入help就可以得到相关的帮助。<br>
<strong>sh</strong>  
sh 由Steve Bourne开发，是Bourne Shell的缩写，sh 是Unix 标准默认的shell。<br>
<strong>ash</strong>  
ash shell 是由Kenneth Almquist编写的，Linux中占用系统资源最少的一个小shell，它只包含24个内部命令，因而使用起来很不方便。<br>
<strong>csh</strong>  
csh 是Linux比较大的内核，它由以William Joy为代表的共计47位作者编成，共有52个内部命令。该shell其实是指向/bin/tcsh这样的一个shell，也就是说，csh其实就是tcsh。<br>
<strong>ksh</strong>  
ksh 是Korn shell的缩写，由Eric Gisin编写，共有42条内部命令。该shell最大的优点是几乎和商业发行版的ksh完全兼容，这样就可以在不用花钱购买商业版本的情况下尝试商业版本的性能了。</p>
<p><code>注意</code>：bash是 Bourne Again Shell 的缩写，是linux标准的默认shell ，它基于Bourne shell，吸收了C shell和Korn shell的一些特性。bash完全兼容sh，也就是说，用sh写的脚本可以不加修改的在bash中执行。</p>
<h5 id="shell3">什么时候使用Shell</h5>
<p><strong>之所以要使用Shell脚本是基于</strong></p>
<ul>
<li>简单性：Shell是一个高级语言；通过它，你可以简洁地表达复杂的操作。</li>
<li>可移植性：使用POSIX所定义的功能，可以做到脚本无须修改就可在不同的系统上执行。</li>
<li>开发容易：可以在短时间内完成一个功能强大又妤用的脚本。</li>
</ul>
<h6 id="shellshell">考虑到Shell脚本的命令限制和效率问题，下列情况一般不使用Shell：</h6>
<ol>
<li>资源密集型的任务，尤其在需要考虑效率时（比如，排序，hash等等）。</li>
<li>需要处理大任务的数学操作，尤其是浮点运算，精确运算，或者复杂的算术运算（这种情况一般使用C++或FORTRAN 来处理）。</li>
<li>有跨平台（操作系统）移植需求（一般使用C 或Java）。</li>
<li>复杂的应用，在必须使用结构化编程的时候（需要变量的类型检查，函数原型，等等）。</li>
<li>对于影响系统全局性的关键任务应用。</li>
<li>对于安全有很高要求的任务，比如你需要一个健壮的系统来防止入侵、破解、恶意破坏等等。</li>
<li>项目由连串的依赖的各个部分组成。</li>
<li>需要大规模的文件操作。</li>
<li>需要多维数组的支持。</li>
<li>需要数据结构的支持，比如链表或数等数据结构。</li>
<li>需要产生或操作图形化界面 GUI。</li>
<li>需要直接操作系统硬件。</li>
<li>需要 I/O 或socket 接口。</li>
</ol>
<hr>
<h5 id="shell4">第一个Shell脚本</h5>
<p>打开文本编辑器，新建一个文件，扩展名为sh（sh代表shell），扩展名并不影响脚本执行，见名知意就好，如果你用php写shell 脚本，扩展名就用php好了。</p>
<p>输入一些代码：</p>
<pre><code>    #!/bin/bash
    echo &quot;Hello World !&quot;
</code></pre><p>“#!” 是一个约定的标记，它告诉系统这个脚本需要什么解释器来执行，即使用哪一种Shell。echo命令用于向窗口输出文本。</p>
<p>运行Shell脚本有两种方法。
作为可执行程序
将上面的代码保存为test.sh，并 cd 到相应目录：</p>
<pre><code>chmod +x ./test.sh  #使脚本具有执行权限
./test.sh  #执行脚本
</code></pre><p>注意，一定要写成./test.sh，而不是test.sh。运行其它二进制的程序也一样，直接写test.sh，linux系统会去PATH里寻找有没有叫test.sh的，而只有/bin, /sbin, /usr/bin，/usr/sbin等在PATH里，你的当前目录通常不在PATH里，所以写成test.sh是会找不到命令的，要用./test.sh告诉系统说，就在当前目录找。</p>
<p>通过这种方式运行bash脚本，第一行一定要写对，好让系统查找到正确的解释器。</p>
<p>这里的&quot;系统&rdquo;，其实就是shell这个应用程序（想象一下Windows Explorer），但我故意写成系统，是方便理解，既然这个系统就是指shell，那么一个使用/bin/sh作为解释器的脚本是不是可以省去第一行呢？是的。
作为解释器参数
这种运行方式是，直接运行解释器，其参数就是shell脚本的文件名，如：</p>
<pre><code>/bin/sh test.sh
/bin/php test.php
</code></pre><p>这种方式运行的脚本，不需要在第一行指定解释器信息，写了也没用。</p>
<p>再看一个例子。下面的脚本使用 read 命令从 stdin 获取输入并赋值给 PERSON 变量，最后在 stdout 上输出：</p>
<pre><code>    #!/bin/bash
    # Author : mozhiyan
    # Copyright (c) http://see.xidian.edu.cn/cpp/linux/
    # Script follows here:
    echo &quot;What is your name?&quot;
    read PERSON
    echo &quot;Hello, $PERSON&quot;
</code></pre><p>运行脚本：</p>
<pre><code>chmod +x ./test.sh
$./test.sh
What is your name?
mozhiyan
Hello, mozhiyan
$
</code></pre><hr>
<h5 id="shell5">Shell变量。</h5>
<p>Shell支持自定义变量。</p>
<h6 id="heading">定义变量</h6>
<p>定义变量时，变量名不加美元符号（$），如：</p>
<pre><code>    variableName=&quot;value&quot;
</code></pre><p><code>注意，变量名和等号之间不能有空格，这可能和你熟悉的所有编程语言都不一样</code>。
同时，变量名的命名须遵循如下规则：</p>
<ul>
<li>首个字符必须为字母（a-z，A-Z）。</li>
<li>中间不能有空格，可以使用下划线（_）。</li>
<li>不能使用标点符号。</li>
<li>不能使用bash里的关键字（可用help命令查看保留关键字）。</li>
</ul>
<p>变量定义举例：</p>
<pre><code>    myUrl=&quot;http://see.xidian.edu.cn/cpp/linux/&quot;
    myNum=100
</code></pre><h6 id="heading1">使用变量</h6>
<p>使用一个定义过的变量，只要在变量名前面加美元符号（$）即可，如：</p>
<pre><code>    your_name=&quot;mozhiyan&quot;
    echo $your_name
    echo ${your_name}
</code></pre><p>变量名外面的花括号是可选的，加不加都行，加花括号是为了帮助解释器识别变量的边界，比如下面这种情况：</p>
<pre><code>    for skill in Ada Coffe Action Java 
    do
        echo &quot;I am good at ${skill}Script&quot;
    done
</code></pre><p>如果不给skill变量加花括号，写成echo &ldquo;I am good at $skillScript&rdquo;，解释器就会把$skillScript当成一个变量（其值为空），代码执行结果就不是我们期望的样子了。</p>
<p>推荐给所有变量加上花括号，这是个好的编程习惯。</p>
<h6 id="heading2">重新定义变量</h6>
<p>已定义的变量，可以被重新定义，如：</p>
<pre><code>    myUrl=&quot;http://see.xidian.edu.cn/cpp/linux/&quot;
    echo ${myUrl}
    myUrl=&quot;http://see.xidian.edu.cn/cpp/shell/&quot;
    echo ${myUrl}
</code></pre><p>这样写是合法的，但注意，第二次赋值的时候不能写 <code>$myUrl=&quot;http://see.xidian.edu.cn/cpp/shell/&quot;</code>，使用变量的时候才加美元符（$）。</p>
<h6 id="heading3">只读变量</h6>
<p>使用 readonly 命令可以将变量定义为只读变量，只读变量的值不能被改变。</p>
<p>下面的例子尝试更改只读变量，结果报错：</p>
<pre><code>    #!/bin/bash
    myUrl=&quot;http://see.xidian.edu.cn/cpp/shell/&quot;
    readonly myUrl
    myUrl=&quot;http://see.xidian.edu.cn/cpp/danpianji/&quot;
</code></pre><p>运行脚本，结果如下：</p>
<pre><code>/bin/sh: NAME: This variable is read only.
</code></pre><h6 id="heading4">删除变量</h6>
<p>使用 unset 命令可以删除变量。语法：</p>
<pre><code>unset variable_name
</code></pre>
<p>变量被删除后不能再次使用；unset 命令不能删除只读变量。</p>
<p>举个例子：</p>
<pre><code>    #!/bin/sh
    myUrl=&quot;http://see.xidian.edu.cn/cpp/u/xitong/&quot;
    unset myUrl
    echo $myUrl
</code></pre><p>上面的脚本没有任何输出。</p>
<h6 id="heading5">变量类型</h6>
<p>运行shell时，会同时存在三种变量：</p>
<ol>
<li>局部变量<br>
局部变量在脚本或命令中定义，仅在当前shell实例中有效，其他shell启动的程序不能访问局部变量。</li>
<li>环境变量<br>
所有的程序，包括shell启动的程序，都能访问环境变量，有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。</li>
<li>shell变量<br>
shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量，有一部分是局部变量，这些变量保证了shell的正常运行</li>
</ol>
<hr>
<h5 id="shell6">Shell特殊变量</h5>
<p>Shell特殊变量：Shell $0, $#, $*, $@, $?, $$和命令行参数
前面已经讲到，变量名只能包含数字、字母和下划线，因为某些包含其他字符的变量有特殊含义，这样的变量被称为特殊变量。</p>
<p>例如，$ 表示当前Shell进程的ID，即pid，看下面的代码：</p>
<pre><code>$echo $$
</code></pre>
<p>运行结果</p>
<p>29949</p>
<p><strong>特殊变量列表</strong></p>
<table>
<thead>
<tr>
<th>变量</th>
<th align="center">含义</th>
</tr>
</thead>
<tbody>
<tr>
<td>$0</td>
<td align="center">当前脚本的文件名</td>
</tr>
<tr>
<td>$n</td>
<td align="center">传递给脚本或函数的参数。n 是一个数字，表示第几个参数。例如，第一个参数是$1，第二个参数是$2。</td>
</tr>
<tr>
<td>$#</td>
<td align="center">传递给脚本或函数的参数个数。</td>
</tr>
<tr>
<td>$*</td>
<td align="center">传递给脚本或函数的所有参数。</td>
</tr>
<tr>
<td>$@</td>
<td align="center">传递给脚本或函数的所有参数。被双引号(&rdquo; &ldquo;)包含时，与 $* 稍有不同，下面将会讲到。</td>
</tr>
<tr>
<td>$?</td>
<td align="center">上个命令的退出状态，或函数的返回值。</td>
</tr>
<tr>
<td>$$</td>
<td align="center">当前Shell进程ID。对于 Shell 脚本，就是这些脚本所在的进程ID。</td>
</tr>
</tbody>
</table>
<h6 id="heading6">命令行参数</h6>
<p>运行脚本时传递给脚本的参数称为命令行参数。命令行参数用 $n 表示，例如，$1 表示第一个参数，$2 表示第二个参数，依次类推。</p>
<p>请看下面的脚本：</p>
<pre><code>    #!/bin/bash
    echo &quot;File Name: $0&quot;
    echo &quot;First Parameter : $1&quot;
    echo &quot;First Parameter : $2&quot;
    echo &quot;Quoted Values: $@&quot;
    echo &quot;Quoted Values: $*&quot;
    echo &quot;Total Number of Parameters : $#&quot;
</code></pre><p>运行结果：</p>
<pre><code>$./test.sh Zara Ali
File Name : ./test.sh
First Parameter : Zara
Second Parameter : Ali
Quoted Values: Zara Ali
Quoted Values: Zara Ali
Total Number of Parameters : 2
</code></pre><h6 id="---">$* 和 $@ 的区别</h6>
<p>$* 和 $@ 都表示传递给函数或脚本的所有参数，不被双引号(&rdquo; &ldquo;)包含时，都以&quot;$1&rdquo; &ldquo;$2&rdquo; … &ldquo;$n&rdquo; 的形式输出所有参数。</p>
<p>但是当它们被双引号(&rdquo; &ldquo;)包含时，&ldquo;$*&rdquo; 会将所有的参数作为一个整体，以&quot;$1 $2 … $n&quot;的形式输出所有参数；&ldquo;$@&rdquo; 会将各个参数分开，以&quot;$1&rdquo; &ldquo;$2&rdquo; … &ldquo;$n&rdquo; 的形式输出所有参数。</p>
<p>下面的例子可以清楚的看到 $* 和 $@ 的区别：</p>
<pre><code>    #!/bin/bash
    echo &quot;\$*=&quot; $*
    echo &quot;\&quot;\$*\&quot;=&quot; &quot;$*&quot;
    echo &quot;\$@=&quot; $@
    echo &quot;\&quot;\$@\&quot;=&quot; &quot;$@&quot;
    echo &quot;print each param from \$*&quot;
    for var in $*
    do
        echo &quot;$var&quot;
    done
    echo &quot;print each param from \$@&quot;
    for var in $@
    do
        echo &quot;$var&quot;
    done
    echo &quot;print each param from \&quot;\$*\&quot;&quot;
    for var in &quot;$*&quot;
    do
        echo &quot;$var&quot;
    done
    echo &quot;print each param from \&quot;\$@\&quot;&quot;
    for var in &quot;$@&quot;
    do
        echo &quot;$var&quot;
    done
</code></pre><p>执行 ./test.sh &ldquo;a&rdquo; &ldquo;b&rdquo; &ldquo;c&rdquo; &ldquo;d&rdquo;，看到下面的结果：</p>
<pre><code>$*=  a b c d
&quot;$*&quot;= a b c d
$@=  a b c d
&quot;$@&quot;= a b c d
print each param from $*
a
b
c
d
print each param from $@
a
b
c
d
print each param from &quot;$*&quot;
a b c d
print each param from &quot;$@&quot;
a
b
c
d
</code></pre><h6 id="heading7">退出状态</h6>
<p>$? 可以获取上一个命令的退出状态。所谓退出状态，就是上一个命令执行后的返回结果。</p>
<p>退出状态是一个数字，一般情况下，大部分命令执行成功会返回 0，失败返回 1。</p>
<p>不过，也有一些命令返回其他值，表示不同类型的错误。</p>
<p>下面例子中，命令成功执行：</p>
<pre><code>$./test.sh Zara Ali
File Name : ./test.sh
First Parameter : Zara
Second Parameter : Ali
Quoted Values: Zara Ali
Quoted Values: Zara Ali
Total Number of Parameters : 2
$echo $?
0
$
</code></pre><p>$? 也可以表示函数的返回值</p>
<hr>
<h5 id="shell7">Shell替换</h5>
<p>Shell替换：Shell变量替换，命令替换，转义字符
如果表达式中包含特殊字符，Shell 将会进行替换。例如，在双引号中使用变量就是一种替换，转义字符也是一种替换。</p>
<p>举个例子：</p>
<pre><code>    #!/bin/bash
    a=10
    echo -e &quot;Value of a is $a \n&quot;
</code></pre><p>运行结果：</p>
<pre><code>Value of a is 10
</code></pre><p>这里 -e 表示对转义字符进行替换。如果不使用 -e 选项，将会原样输出：</p>
<pre><code>Value of a is 10\n
</code></pre><p><strong>下面的转义字符都可以用在 echo 中：</strong></p>
<table>
<thead>
<tr>
<th>转义字符</th>
<th align="center">含义</th>
</tr>
</thead>
<tbody>
<tr>
<td>\</td>
<td align="center">反斜杠</td>
</tr>
<tr>
<td>\a</td>
<td align="center">警报，响铃</td>
</tr>
<tr>
<td>\b</td>
<td align="center">退格（删除键）</td>
</tr>
<tr>
<td>\f</td>
<td align="center">换页(FF)，将当前位置移到下页开头</td>
</tr>
<tr>
<td>\n</td>
<td align="center">换行</td>
</tr>
<tr>
<td>\r</td>
<td align="center">回车</td>
</tr>
<tr>
<td>\t</td>
<td align="center">水平制表符（tab键）</td>
</tr>
<tr>
<td>\v</td>
<td align="center">垂直制表符</td>
</tr>
</tbody>
</table>
<p>可以使用 echo 命令的 -E 选项禁止转义，默认也是不转义的；使用 -n 选项可以禁止插入换行符。
命令替换
命令替换是指Shell可以先执行命令，将输出结果暂时保存，在适当的地方输出。</p>
<p>命令替换的语法：</p>
<pre><code>`command`
</code></pre>
<p>注意是反引号，不是单引号，这个键位于 Esc 键下方。</p>
<p>下面的例子中，将命令执行结果保存在变量中：</p>
<pre><code>    #!/bin/bash
    DATE=`date`
    echo &quot;Date is $DATE&quot;
    USERS=`who | wc -l`
    echo &quot;Logged in user are $USERS&quot;
    UP=`date ; uptime`
    echo &quot;Uptime is $UP&quot;
</code></pre><p>运行结果：</p>
<pre><code>Date is Thu Jul  2 03:59:57 MST 2009
Logged in user are 1
Uptime is Thu Jul  2 03:59:57 MST 2009
03:59:57 up 20 days, 14:03,  1 user,  load avg: 0.13, 0.07, 0.15
</code></pre><p>变量替换
变量替换可以根据变量的状态（是否为空、是否定义等）来改变它的值</p>
<p>可以使用的变量替换形式：
形式 	说明
${var} 	变量本来的值
${var:-word} 	如果变量 var 为空或已被删除(unset)，那么返回 word，但不改变 var 的值。
${var:=word} 	如果变量 var 为空或已被删除(unset)，那么返回 word，并将 var 的值设置为 word。
${var:?message} 	如果变量 var 为空或已被删除(unset)，那么将消息 message 送到标准错误输出，可以用来检测变量 var 是否可以被正常赋值。
若此替换出现在Shell脚本中，那么脚本将停止运行。
${var:+word} 	如果变量 var 被定义，那么返回 word，但不改变 var 的值。</p>
<p>请看下面的例子：</p>
<p>#!/bin/bash</p>
<pre><code>echo ${var:-&quot;Variable is not set&quot;}
echo &quot;1 - Value of var is ${var}&quot;

echo ${var:=&quot;Variable is not set&quot;}
echo &quot;2 - Value of var is ${var}&quot;

unset var
echo ${var:+&quot;This is default value&quot;}
echo &quot;3 - Value of var is $var&quot;

var=&quot;Prefix&quot;
echo ${var:+&quot;This is default value&quot;}
echo &quot;4 - Value of var is $var&quot;

echo ${var:?&quot;Print this message&quot;}
echo &quot;5 - Value of var is ${var}&quot;
</code></pre><p>运行结果：</p>
<p>纯文本复制</p>
<pre><code>    Variable is not set
    1 - Value of var is
    Variable is not set
    2 - Value of var is Variable is not set
    3 - Value of var is
    This is default value
    4 - Value of var is Prefix
    Prefix
    5 - Value of var is Prefix
</code></pre><hr>
<h5 id="shell8">Shell运算符</h5>
<p>Shell运算符：Shell算数运算符、关系运算符、布尔运算符、字符串运算符等<br>
Bash 支持很多运算符，包括算数运算符、关系运算符、布尔运算符、字符串运算符和文件测试运算符。</p>
<p>原生bash不支持简单的数学运算，但是可以通过其他命令来实现，例如 awk 和 expr，expr 最常用。</p>
<p>expr 是一款表达式计算工具，使用它能完成表达式的求值操作。</p>
<p>例如，两个数相加：</p>
<pre><code>    #!/bin/bash
    val=`expr 2 + 2`
    echo &quot;Total value : $val&quot;
</code></pre><p>运行脚本输出：</p>
<pre><code>Total value : 4
</code></pre><p>两点注意：</p>
<pre><code>表达式和运算符之间要有空格，例如 2+2 是不对的，必须写成 2 + 2，这与我们熟悉的大多数编程语言不一样。
完整的表达式要被 ` ` 包含，注意这个字符不是常用的单引号，在 Esc 键下边。
</code></pre>
<p>算术运算符
先来看一个使用算术运算符的例子：</p>
<pre><code>    #!/bin/sh
    a=10
    b=20
    val=`expr $a + $b`
    echo &quot;a + b : $val&quot;
    val=`expr $a - $b`
    echo &quot;a - b : $val&quot;
    val=`expr $a \* $b`
    echo &quot;a * b : $val&quot;
    val=`expr $b / $a`
    echo &quot;b / a : $val&quot;
    val=`expr $b % $a`
    echo &quot;b % a : $val&quot;
    if [ $a == $b ]
    then
       echo &quot;a is equal to b&quot;
    fi
    if [ $a != $b ]
    then
       echo &quot;a is not equal to b&quot;
    fi
</code></pre><p>运行结果：</p>
<pre><code>a + b : 30
a - b : -10
a * b : 200
b / a : 2
b % a : 0
a is not equal to b
</code></pre><p>注意：</p>
<pre><code>乘号(*)前边必须加反斜杠(\)才能实现乘法运算；
if...then...fi 是条件语句，后续将会讲解。
</code></pre>
<p><strong>算术运算符列表</strong></p>
<table>
<thead>
<tr>
<th>运算符</th>
<th align="right">说明</th>
<th align="center">举例</th>
</tr>
</thead>
<tbody>
<tr>
<td>+</td>
<td align="right">加法</td>
<td align="center"><code>expr $a + $b</code> 结果为 30。</td>
</tr>
<tr>
<td>-</td>
<td align="right">减法</td>
<td align="center"><code>expr $a - $b</code> 结果为 10。</td>
</tr>
<tr>
<td>*</td>
<td align="right">乘法</td>
<td align="center"><code>expr $a \* $b</code> 结果为  200。</td>
</tr>
<tr>
<td>/</td>
<td align="right">除法</td>
<td align="center"><code>expr $b / $a</code> 结果为 2。</td>
</tr>
<tr>
<td>%</td>
<td align="right">取余</td>
<td align="center"><code>expr $b % $a</code> 结果为 0。</td>
</tr>
<tr>
<td>=</td>
<td align="right">赋值</td>
<td align="center">a=$b 将把变量 b 的值赋给 a。</td>
</tr>
<tr>
<td>==</td>
<td align="right">相等。用于比较两个数字，相同则返回 true。</td>
<td align="center">[ $a == $b ] 返回 false。</td>
</tr>
<tr>
<td>!=</td>
<td align="right">不相等。用于比较两个数字，不相同则返回 true。</td>
<td align="center">[ $a != $b ] 返回 true。</td>
</tr>
</tbody>
</table>
<p>注意：条件表达式要放在方括号之间，并且要有空格，例如 [$a==$b] 是错误的，必须写成 [ $a == $b ]。
关系运算符
关系运算符只支持数字，不支持字符串，除非字符串的值是数字。</p>
<p>先来看一个关系运算符的例子：</p>
<pre><code>    #!/bin/sh
    a=10
    b=20
    if [ $a -eq $b ]
    then
       echo &quot;$a -eq $b : a is equal to b&quot;
    else
       echo &quot;$a -eq $b: a is not equal to b&quot;
    fi
    if [ $a -ne $b ]
    then
       echo &quot;$a -ne $b: a is not equal to b&quot;
    else
       echo &quot;$a -ne $b : a is equal to b&quot;
    fi
    if [ $a -gt $b ]
    then
       echo &quot;$a -gt $b: a is greater than b&quot;
    else
       echo &quot;$a -gt $b: a is not greater than b&quot;
    fi
    if [ $a -lt $b ]
    then
       echo &quot;$a -lt $b: a is less than b&quot;
    else
       echo &quot;$a -lt $b: a is not less than b&quot;
    fi
    if [ $a -ge $b ]
    then
       echo &quot;$a -ge $b: a is greater or  equal to b&quot;
    else
       echo &quot;$a -ge $b: a is not greater or equal to b&quot;
    fi
    if [ $a -le $b ]
    then
       echo &quot;$a -le $b: a is less or  equal to b&quot;
    else
       echo &quot;$a -le $b: a is not less or equal to b&quot;
    fi
</code></pre><p>运行结果：</p>
<pre><code>10 -eq 20: a is not equal to b
10 -ne 20: a is not equal to b
10 -gt 20: a is not greater than b
10 -lt 20: a is less than b
10 -ge 20: a is not greater or equal to b
10 -le 20: a is less or  equal to b
</code></pre><p><strong>关系运算符列表</strong></p>
<table>
<thead>
<tr>
<th>运算符</th>
<th align="right">说明</th>
<th align="center">举例</th>
</tr>
</thead>
<tbody>
<tr>
<td>-eq</td>
<td align="right">检测两个数是否相等，相等返回 true。</td>
<td align="center">[ $a -eq $b ] 返回 true。</td>
</tr>
<tr>
<td>-ne</td>
<td align="right">检测两个数是否相等，不相等返回 true。</td>
<td align="center">[ $a -ne $b ] 返回 true。</td>
</tr>
<tr>
<td>-gt</td>
<td align="right">检测左边的数是否大于右边的，如果是，则返回 true。</td>
<td align="center">[ $a -gt $b ] 返回 false。</td>
</tr>
<tr>
<td>-lt</td>
<td align="right">检测左边的数是否小于右边的，如果是，则返回 true。</td>
<td align="center">[ $a -lt $b ] 返回 true。</td>
</tr>
<tr>
<td>-ge</td>
<td align="right">检测左边的数是否大等于右边的，如果是，则返回 true。</td>
<td align="center">[ $a -ge $b ] 返回 false。</td>
</tr>
<tr>
<td>-le</td>
<td align="right">检测左边的数是否小于等于右边的，如果是，则返回 true。</td>
<td align="center">[ $a -le $b ] 返回 true。</td>
</tr>
<tr>
<td>布尔运算符</td>
<td></td>
<td></td>
</tr>
<tr>
<td>先来看一个布尔运算符的例子：</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<pre><code>    #!/bin/sh
    a=10
    b=20
    if [ $a != $b ]
    then
       echo &quot;$a != $b : a is not equal to b&quot;
    else
       echo &quot;$a != $b: a is equal to b&quot;
    fi
    if [ $a -lt 100 -a $b -gt 15 ]
    then
       echo &quot;$a -lt 100 -a $b -gt 15 : returns true&quot;
    else
       echo &quot;$a -lt 100 -a $b -gt 15 : returns false&quot;
    fi
    if [ $a -lt 100 -o $b -gt 100 ]
    then
       echo &quot;$a -lt 100 -o $b -gt 100 : returns true&quot;
    else
       echo &quot;$a -lt 100 -o $b -gt 100 : returns false&quot;
    fi
    if [ $a -lt 5 -o $b -gt 100 ]
    then
       echo &quot;$a -lt 100 -o $b -gt 100 : returns true&quot;
    else
       echo &quot;$a -lt 100 -o $b -gt 100 : returns false&quot;
    fi
</code></pre><p>运行结果：</p>
<pre><code>10 != 20 : a is not equal to b
10 -lt 100 -a 20 -gt 15 : returns true
10 -lt 100 -o 20 -gt 100 : returns true
10 -lt 5 -o 20 -gt 100 : returns false
</code></pre><p>布尔运算符列表 运算符 	说明 	举例
! 	非运算，表达式为 true 则返回 false，否则返回 true。 	[ ! false ] 返回 true。
-o 	或运算，有一个表达式为 true 则返回 true。 	[ $a -lt 20 -o $b -gt 100 ] 返回 true。
-a 	与运算，两个表达式都为 true 才返回 true。 	[ $a -lt 20 -a $b -gt 100 ] 返回 false。
字符串运算符
先来看一个例子：</p>
<pre><code>    #!/bin/sh
    a=&quot;abc&quot;
    b=&quot;efg&quot;
    if [ $a = $b ]
    then
       echo &quot;$a = $b : a is equal to b&quot;
    else
       echo &quot;$a = $b: a is not equal to b&quot;
    fi
    if [ $a != $b ]
    then
       echo &quot;$a != $b : a is not equal to b&quot;
    else
       echo &quot;$a != $b: a is equal to b&quot;
    fi
    if [ -z $a ]
    then
       echo &quot;-z $a : string length is zero&quot;
    else
       echo &quot;-z $a : string length is not zero&quot;
    fi
    if [ -n $a ]
    then
       echo &quot;-n $a : string length is not zero&quot;
    else
       echo &quot;-n $a : string length is zero&quot;
    fi
    if [ $a ]
    then
       echo &quot;$a : string is not empty&quot;
    else
       echo &quot;$a : string is empty&quot;
    fi
</code></pre><p>运行结果：</p>
<pre><code>abc = efg: a is not equal to b
abc != efg : a is not equal to b
-z abc : string length is not zero
-n abc : string length is not zero
abc : string is not empty
</code></pre><p>字符串运算符列表 运算符 	说明 	举例</p>
<ul>
<li>= 	检测两个字符串是否相等，相等返回 true。 	[ $a = $b ] 返回 false。</li>
<li>!= 	检测两个字符串是否相等，不相等返回 true。 	[ $a != $b ] 返回 true。</li>
<li>-z 	检测字符串长度是否为0，为0返回 true。 	[ -z $a ] 返回 false。</li>
<li>-n 	检测字符串长度是否为0，不为0返回 true。 	[ -z $a ] 返回 true。</li>
<li>str 	检测字符串是否为空，不为空返回 true。 	[ $a ] 返回 true。
文件测试运算符
文件测试运算符用于检测 Unix 文件的各种属性。</li>
</ul>
<p>例如，变量 file 表示文件“/var/www/tutorialspoint/unix/test.sh”，它的大小为100字节，具有 rwx 权限。下面的代码，将检测该文件的各种属性：</p>
<pre><code>    #!/bin/sh
    file=&quot;/var/www/tutorialspoint/unix/test.sh&quot;
    if [ -r $file ]
    then
       echo &quot;File has read access&quot;
    else
       echo &quot;File does not have read access&quot;
    fi
    if [ -w $file ]
    then
       echo &quot;File has write permission&quot;
    else
       echo &quot;File does not have write permission&quot;
    fi
    if [ -x $file ]
    then
       echo &quot;File has execute permission&quot;
    else
       echo &quot;File does not have execute permission&quot;
    fi
    if [ -f $file ]
    then
       echo &quot;File is an ordinary file&quot;
    else
       echo &quot;This is sepcial file&quot;
    fi
    if [ -d $file ]
    then
       echo &quot;File is a directory&quot;
    else
       echo &quot;This is not a directory&quot;
    fi
    if [ -s $file ]
    then
       echo &quot;File size is zero&quot;
    else
       echo &quot;File size is not zero&quot;
    fi
    if [ -e $file ]
    then
       echo &quot;File exists&quot;
    else
       echo &quot;File does not exist&quot;
    fi
</code></pre><p>运行结果：</p>
<pre><code>File has read access
File has write permission
File has execute permission
File is an ordinary file
This is not a directory
File size is zero
File exists
</code></pre><p>文件测试运算符列表 操作符 	说明 	举例
|   参数     | 说明		|
| &mdash;&mdash;&ndash;   |:&mdash;-:   |
-b file 	检测文件是否是块设备文件，如果是，则返回 true。 	[ -b $file ] 返回 false。</p>
<ul>
<li>-c file 	检测文件是否是字符设备文件，如果是，则返回 true。 	[ -b $file ] 返回 false。</li>
<li>-d file 	检测文件是否是目录，如果是，则返回 true。 	[ -d $file ] 返回 false。</li>
<li>-f file 	检测文件是否是普通文件（既不是目录，也不是设备文件），如果是，则返回 true。 	[ -f $file ] 返回 true。</li>
<li>-g file 	检测文件是否设置了 SGID 位，如果是，则返回 true。 	[ -g $file ] 返回 false。</li>
<li>-k file 	检测文件是否设置了粘着位(Sticky Bit)，如果是，则返回 true。 	[ -k $file ] 返回 false。</li>
<li>-p file 	检测文件是否是具名管道，如果是，则返回 true。 	[ -p $file ] 返回 false。</li>
<li>-u file 	检测文件是否设置了 SUID 位，如果是，则返回 true。 	[ -u $file ] 返回 false。</li>
<li>-r file 	检测文件是否可读，如果是，则返回 true。 	[ -r $file ] 返回 true。</li>
<li>-w file 	检测文件是否可写，如果是，则返回 true。 	[ -w $file ] 返回 true。</li>
<li>-x file 	检测文件是否可执行，如果是，则返回 true。 	[ -x $file ] 返回 true。</li>
<li>-s file 	检测文件是否为空（文件大小是否大于0），不为空返回 true。 	[ -s $file ] 返回 true。</li>
<li>-e file 	检测文件（包括目录）是否存在，如果是，则返回 true。 	[ -e $file ] 返回 true。</li>
</ul>
<hr>
<h5 id="shell9">Shell注释</h5>
<p>以“#”开头的行就是注释，会被解释器忽略。
sh里没有多行注释，只能每一行加一个#号。</p>
<hr>
<h5 id="shell10">Shell字符串</h5>
<p>字符串是shell编程中最常用最有用的数据类型（除了数字和字符串，也没啥其它类型好用了），字
符串可以用单引号，也可以用双引号，也可以不用引号。单双引号的区别跟PHP类似。</p>
<h6 id="heading8">单引号</h6>
<p>单引号字符串的限制：</p>
<ul>
<li>单引号里的任何字符都会原样输出，单引号字符串中的变量是无效的；</li>
<li>单引号字串中不能出现单引号（对单引号使用转义符后也不行）。</li>
</ul>
<h6 id="heading9">双引号</h6>
<p>双引号的优点：</p>
<ul>
<li>双引号里可以有变量</li>
<li>双引号里可以出现转义字符</li>
</ul>
<h6 id="heading10">拼接字符串</h6>
<pre><code>    your_name=&quot;qinjx&quot;
    greeting=&quot;hello, &quot;$your_name&quot; !&quot;
    greeting_1=&quot;hello, ${your_name} !&quot;
    echo $greeting $greeting_1
</code></pre><h6 id="heading11">获取字符串长度</h6>
<pre><code>    string=&quot;abcd&quot;
    echo ${#string} #输出 4
</code></pre><h6 id="heading12">提取子字符串</h6>
<pre><code>    string=&quot;alibaba is a great company&quot;
    echo ${string:1:4} #输出liba
</code></pre><h6 id="heading13">查找子字符串</h6>
<pre><code>    string=&quot;alibaba is a great company&quot;
    echo `expr index &quot;$string&quot; is`
</code></pre><hr>
<h5 id="shell11">Shell数组</h5>
<p>Shell数组：shell数组的定义、数组长度<br>
Shell在编程方面比Windows批处理强大很多，无论是在循环、运算。</p>
<p>bash支持一维数组（不支持多维数组），并且没有限定数组的大小。类似与C语言，数组元素的下标由0开始编号。获取数组中的元素要利用下标，下标可以是整数或算术表达式，其值应大于或等于0。</p>
<h6 id="heading14">定义数组</h6>
<p>在Shell中，用括号来表示数组，数组元素用“空格”符号分割开。定义数组的一般形式为：
array_name=(value1 &hellip; valuen)
例如：</p>
<pre><code>    array_name=(value0 value1 value2 value3)
</code></pre><p>或者</p>
<pre><code>    array_name=(
    value0
    value1
    value2
    value3
    )
</code></pre><p>还可以单独定义数组的各个分量：</p>
<pre><code>    array_name[0]=value0
    array_name[1]=value1
    array_name[2]=value2
</code></pre><p>可以不使用连续的下标，而且下标的范围没有限制。</p>
<h6 id="heading15">读取数组</h6>
<p>读取数组元素值的一般格式是：
${array_name[index]}
例如：</p>
<pre><code>    valuen=${array_name[2]}
</code></pre><p>举个例子：</p>
<pre><code>    #!/bin/sh
    NAME[0]=&quot;Zara&quot;
    NAME[1]=&quot;Qadir&quot;
    NAME[2]=&quot;Mahnaz&quot;
    NAME[3]=&quot;Ayan&quot;
    NAME[4]=&quot;Daisy&quot;
    echo &quot;First Index: ${NAME[0]}&quot;
    echo &quot;Second Index: ${NAME[1]}&quot;
</code></pre><p>运行脚本，输出：</p>
<pre><code>$./test.sh
First Index: Zara
Second Index: Qadir
</code></pre><p>使用@ 或 * 可以获取数组中的所有元素，例如：</p>
<pre><code>    ${array_name[*]}
    ${array_name[@]}
</code></pre><p>举个例子：</p>
<pre><code>    #!/bin/sh
    NAME[0]=&quot;Zara&quot;
    NAME[1]=&quot;Qadir&quot;
    NAME[2]=&quot;Mahnaz&quot;
    NAME[3]=&quot;Ayan&quot;
    NAME[4]=&quot;Daisy&quot;
    echo &quot;First Method: ${NAME[*]}&quot;
    echo &quot;Second Method: ${NAME[@]}&quot;
</code></pre><p>运行脚本，输出：</p>
<pre><code>$./test.sh
First Method: Zara Qadir Mahnaz Ayan Daisy
Second Method: Zara Qadir Mahnaz Ayan Daisy
</code></pre><h6 id="heading16">获取数组的长度</h6>
<p>获取数组长度的方法与获取字符串长度的方法相同，例如：</p>
<pre><code>    # 取得数组元素的个数
    length=${#array_name[@]}
    # 或者
    length=${#array_name[*]}
    # 取得数组单个元素的长度
    lengthn=${#array_name[n]}
</code></pre><hr>
<h5 id="shell-echo">Shell echo命令</h5>
<p>echo是Shell的一个内部指令，用于在屏幕上打印出指定的字符串。命令格式：</p>
<pre><code>echo arg
</code></pre>
<p>您可以使用echo实现更复杂的输出格式控制。
显示转义字符</p>
<pre><code>    echo &quot;\&quot;It is a test\&quot;&quot;
</code></pre><p>结果将是：</p>
<pre><code>&quot;It is a test&quot;
</code></pre><p>双引号也可以省略。
显示变量</p>
<pre><code>name=&quot;OK&quot;
echo &quot;$name It is a test&quot;
</code></pre>
<p>结果将是：
OK It is a test</p>
<p>同样双引号也可以省略。</p>
<p>如果变量与其它字符相连的话，需要使用大括号（{ }）：</p>
<pre><code>mouth=8
echo &quot;${mouth}-1-2009&quot;
</code></pre>
<p>结果将是：
8-1-2009
显示换行</p>
<pre><code>echo &quot;OK!\n&quot;
echo &quot;It is a test&quot;
</code></pre>
<p>输出：
OK!
It is a test
显示不换行</p>
<pre><code>echo &quot;OK!\c&quot;
echo &quot;It is a test&quot;
</code></pre>
<p>输出：
OK!It si a test
显示结果重定向至文件</p>
<pre><code>echo &quot;It is a test&quot; &gt; myfile
</code></pre>
<p>原样输出字符串
若需要原样输出字符串（不进行转义），请使用单引号。例如：</p>
<pre><code>    echo '$name\&quot;'
</code></pre><p>显示命令执行结果</p>
<pre><code>    echo `date`
</code></pre><p>结果将显示当前日期</p>
<hr>
<h5 id="shell-printf">shell printf命令</h5>
<p>shell printf命令：格式化输出语句<br>
printf 命令用于格式化输出， 是echo命令的增强版。它是C语言printf()库函数的一个有限的变形，并且在语法上有些不同。</p>
<p>注意：printf 由 POSIX 标准所定义，移植性要比 echo 好。
这里仅说明与C语言printf()函数的不同：</p>
<ul>
<li>printf 命令不用加括号</li>
<li>format-string 可以没有引号，但最好加上，单引号双引号均可。</li>
<li>参数多于格式控制符(%)时，format-string 可以重用，可以将所有参数都转换。</li>
<li>arguments 使用空格分隔，不用逗号。</li>
</ul>
<hr>
<h5 id="shell-if-else">Shell if else语句</h5>
<p>if 语句通过关系运算符判断表达式的真假来决定执行哪个分支。Shell 有三种 if &hellip; else 语句：</p>
<pre><code>    if ... fi 语句；
    if ... else ... fi 语句；
    if ... elif ... else ... fi 语句。
</code></pre><h6 id="1if--else-">1)if &hellip; else 语句</h6>
<p>if &hellip; else 语句的语法：</p>
<pre><code>if [ expression ]
then
   Statement(s) to be executed if expression is true
fi
</code></pre><p>如果 expression 返回 true，then 后边的语句将会被执行；如果返回 false，不会执行任何语句。</p>
<p>最后必须以 fi 来结尾闭合 if，fi 就是 if 倒过来拼写，后面也会遇见。</p>
<p>注意：expression 和方括号([ ])之间必须有空格，否则会有语法错误。</p>
<p>举个例子：</p>
<pre><code>    #!/bin/sh
    a=10
    b=20
    if [ $a == $b ]
    then
       echo &quot;a is equal to b&quot;
    fi
    if [ $a != $b ]
    then
       echo &quot;a is not equal to b&quot;
    fi
</code></pre><p>运行结果：</p>
<pre><code>a is not equal to b
</code></pre><h6 id="2-if--else--fi-">2) if &hellip; else &hellip; fi 语句</h6>
<p>if &hellip; else &hellip; fi 语句的语法：</p>
<pre><code>if [ expression ]
then
   Statement(s) to be executed if expression is true
else
   Statement(s) to be executed if expression is not true
fi
</code></pre><p>如果 expression 返回 true，那么 then 后边的语句将会被执行；否则，执行 else 后边的语句。</p>
<p>举个例子：</p>
<pre><code>    #!/bin/sh
    a=10
    b=20
    if [ $a == $b ]
    then
       echo &quot;a is equal to b&quot;
    else
       echo &quot;a is not equal to b&quot;
    fi
</code></pre><p>执行结果：</p>
<pre><code>a is not equal to b
</code></pre><h6 id="3-if--elif--fi-">3) if &hellip; elif &hellip; fi 语句</h6>
<p>if &hellip; elif &hellip; fi 语句可以对多个条件进行判断，语法为：</p>
<pre><code>if [ expression 1 ]
then
   Statement(s) to be executed if expression 1 is true
elif [ expression 2 ]
then
   Statement(s) to be executed if expression 2 is true
elif [ expression 3 ]
then
   Statement(s) to be executed if expression 3 is true
else
   Statement(s) to be executed if no expression is true
fi
</code></pre><p>哪一个 expression 的值为 true，就执行哪个 expression 后面的语句；如果都为 false，那么不执行任何语句。</p>
<p>举个例子：</p>
<pre><code>    #!/bin/sh
    a=10
    b=20
    if [ $a == $b ]
    then
       echo &quot;a is equal to b&quot;
    elif [ $a -gt $b ]
    then
       echo &quot;a is greater than b&quot;
    elif [ $a -lt $b ]
    then
       echo &quot;a is less than b&quot;
    else
       echo &quot;None of the condition met&quot;
    fi
</code></pre><p>运行结果：</p>
<pre><code>a is less than b
</code></pre><p>if &hellip; else 语句也可以写成一行，以命令的方式来运行，像这样：</p>
<pre><code>if test $[2*3] -eq $[1+5]; then echo 'The two numbers are equal!'; fi;
</code></pre>
<p>if &hellip; else 语句也经常与 test 命令结合使用，如下所示：</p>
<pre><code>    num1=$[2*3]
    num2=$[1+5]
    if test $[num1] -eq $[num2]
    then
        echo 'The two numbers are equal!'
    else
        echo 'The two numbers are not equal!'
    fi
</code></pre><p>输出：</p>
<pre><code>The two numbers are equal!
</code></pre><p>test 命令用于检查某个条件是否成立，与方括号([ ])类似。</p>
<hr>
<h5 id="shell-test">Shell test命令</h5>
<p>Shell中的 test 命令用于检查某个条件是否成立，它可以进行数值、字符和文件三个方面的测试。</p>
<h6 id="heading17">数值测试</h6>
<table>
<thead>
<tr>
<th>参数</th>
<th align="center">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>-eq</td>
<td align="center">等于则为真</td>
</tr>
<tr>
<td>-ne</td>
<td align="center">不等于则为真</td>
</tr>
<tr>
<td>-gt</td>
<td align="center">大于则为真</td>
</tr>
<tr>
<td>-ge</td>
<td align="center">大于等于则为真</td>
</tr>
<tr>
<td>-lt</td>
<td align="center">小于则为真</td>
</tr>
<tr>
<td>-le</td>
<td align="center">小于等于则为真</td>
</tr>
</tbody>
</table>
<p>例如：</p>
<pre><code>    num1=100
    num2=100
    if test $[num1] -eq $[num2]
    then
        echo 'The two numbers are equal!'
    else
        echo 'The two numbers are not equal!'
    fi
</code></pre><p>输出：
The two numbers are equal!</p>
<h6 id="heading18">字符串测试</h6>
<table>
<thead>
<tr>
<th>参数</th>
<th align="center">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>=</td>
<td align="center">等于则为真</td>
</tr>
<tr>
<td>!=</td>
<td align="center">不相等则为真</td>
</tr>
<tr>
<td>-z 字符串</td>
<td align="center">字符串长度伪则为真</td>
</tr>
<tr>
<td>-n 字符串</td>
<td align="center">字符串长度不伪则为真</td>
</tr>
</tbody>
</table>
<p>例如：</p>
<pre><code>    num1=100
    num2=100
    if test num1=num2
    then
        echo 'The two strings are equal!'
    else
        echo 'The two strings are not equal!'
    fi
</code></pre><p>输出：
The two strings are equal!</p>
<h6 id="heading19">文件测试</h6>
<table>
<thead>
<tr>
<th>参数</th>
<th align="center">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>-e 文件名</td>
<td align="center">如果文件存在则为真</td>
</tr>
<tr>
<td>-r 文件名</td>
<td align="center">如果文件存在且可读则为真</td>
</tr>
<tr>
<td>-w 文件名</td>
<td align="center">如果文件存在且可写则为真</td>
</tr>
<tr>
<td>-x 文件名</td>
<td align="center">如果文件存在且可执行则为真</td>
</tr>
<tr>
<td>-s 文件名</td>
<td align="center">如果文件存在且至少有一个字符则为真</td>
</tr>
<tr>
<td>-d 文件名</td>
<td align="center">如果文件存在且为目录则为真</td>
</tr>
<tr>
<td>-f 文件名</td>
<td align="center">如果文件存在且为普通文件则为真</td>
</tr>
<tr>
<td>-c 文件名</td>
<td align="center">如果文件存在且为字符型特殊文件则为真</td>
</tr>
<tr>
<td>-b 文件名</td>
<td align="center">如果文件存在且为块特殊文件则为真</td>
</tr>
</tbody>
</table>
<p>例如：</p>
<pre><code>    cd /bin
    if test -e ./bash
    then
        echo 'The file already exists!'
    else
        echo 'The file does not exists!'
    fi
</code></pre><p>输出：
The file already exists!</p>
<p>另外，Shell还提供了与( ! )、或( -o )、非( -a )三个逻辑操作符用于将测试条件连接起来，其优先级为：“!”最高，“-a”次之，“-o”最低。例如：</p>
<pre><code>    cd /bin
    if test -e ./notFile -o ./bash
    then
        echo 'One file exists at least!'
    else
        echo 'Both dose not exists!'
    fi
</code></pre><p>输出：</p>
<pre><code>One file exists at least!
</code></pre><hr>
<h5 id="shell-case-esac">Shell case esac语句</h5>
<p>case &hellip; esac 与其他语言中的 switch &hellip; case 语句类似，是一种多分枝选择结构。</p>
<p>case 语句匹配一个值或一个模式，如果匹配成功，执行相匹配的命令。case语句格式如下：</p>
<pre><code>case 值 in
模式1)
    command1
    command2
    command3
    ;;
模式2）
    command1
    command2
    command3
    ;;
*)
    command1
    command2
    command3
    ;;
esac
</code></pre><p>case工作方式如上所示。取值后面必须为关键字 in，每一模式必须以右括号结束。取值可以为变量或常数。匹配发现取值符合某一模式后，其间所有命令开始执行直至 ;;。;; 与其他语言中的 break 类似，意思是跳到整个 case 语句的最后。</p>
<p>取值将检测匹配的每一个模式。一旦模式匹配，则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式，使用星号 * 捕获该值，再执行后面的命令。</p>
<p>下面的脚本提示输入1到4，与每一种模式进行匹配：</p>
<pre><code>    echo 'Input a number between 1 to 4'
    echo 'Your number is:\c'
    read aNum
    case $aNum in
        1)  echo 'You select 1'
        ;;
        2)  echo 'You select 2'
        ;;
        3)  echo 'You select 3'
        ;;
        4)  echo 'You select 4'
        ;;
        *)  echo 'You do not select a number between 1 to 4'
        ;;
    esac
</code></pre><p>输入不同的内容，会有不同的结果，例如：</p>
<pre><code>Input a number between 1 to 4
Your number is:3
You select 3
</code></pre><hr>
<h5 id="shell-for">Shell for循环</h5>
<p>与其他编程语言类似，Shell支持for循环。</p>
<p>for循环一般格式为：</p>
<pre><code>for 变量 in 列表
do
    command1
    command2
    ...
    commandN
done
</code></pre><p>列表是一组值（数字、字符串等）组成的序列，每个值通过空格分隔。每循环一次，就将列表中的下一个值赋给变量。</p>
<p>in 列表是可选的，如果不用它，for 循环使用命令行的位置参数。</p>
<p>例如，顺序输出当前列表中的数字：</p>
<pre><code>    for loop in 1 2 3 4 5
    do
        echo &quot;The value is: $loop&quot;
    done
</code></pre><p>运行结果：</p>
<pre><code>The value is: 1
The value is: 2
The value is: 3
The value is: 4
The value is: 5
</code></pre><p>顺序输出字符串中的字符：</p>
<pre><code>    for str in 'This is a string'
    do
        echo $str
    done
</code></pre><p>运行结果：</p>
<pre><code>This is a string
</code></pre><p>显示主目录下以 .bash 开头的文件：</p>
<pre><code>    #!/bin/bash
    for FILE in $HOME/.bash*
    do
       echo $FILE
    done
</code></pre><p>运行结果：</p>
<pre><code>/root/.bash_history
/root/.bash_logout
/root/.bash_profile
/root/.bashrc
</code></pre><hr>
<h5 id="shell-while">Shell while循环</h5>
<p>while循环用于不断执行一系列命令，也用于从输入文件中读取数据；命令通常为测试条件。其格式为：</p>
<pre><code>while command
do
   Statement(s) to be executed if command is true
done
</code></pre><p>命令执行完毕，控制返回循环顶部，从头开始直至测试条件为假。</p>
<p>以下是一个基本的while循环，测试条件是：如果COUNTER小于5，那么返回 true。COUNTER从0开始，每次循环处理时，COUNTER加1。运行上述脚本，返回数字1到5，然后终止。</p>
<pre><code>    COUNTER=0
    while [ $COUNTER -lt 5 ]
    do
        COUNTER='expr $COUNTER+1'
        echo $COUNTER
    done
</code></pre><p>运行脚本，输出：</p>
<pre><code>1
2
3
4
5
</code></pre><p>while循环可用于读取键盘信息。下面的例子中，输入信息被设置为变量FILM，按<!-- raw HTML omitted -->结束循环。</p>
<pre><code>    echo 'type &lt;CTRL-D&gt; to terminate'
    echo -n 'enter your most liked film: '
    while read FILM
    do
        echo &quot;Yeah! great film the $FILM&quot;
    done
</code></pre><p>运行脚本，输出类似下面：</p>
<pre><code>type &lt;CTRL-D&gt; to terminate
enter your most liked film: Sound of Music
Yeah! great film the Sound of Music
</code></pre><hr>
<h5 id="shell-until">Shell until循环</h5>
<p>until 循环执行一系列命令直至条件为 true 时停止。until 循环与 while 循环在处理方式上刚好相反。一般while循环优于until循环，但在某些时候，也只是极少数情况下，until 循环更加有用。</p>
<p>until 循环格式为：</p>
<pre><code>until command
do
   Statement(s) to be executed until command is true
done
</code></pre><p>command 一般为条件表达式，如果返回值为 false，则继续执行循环体内的语句，否则跳出循环。</p>
<p>例如，使用 until 命令输出 0 ~ 9 的数字：</p>
<pre><code>    #!/bin/bash
    a=0
    until [ ! $a -lt 5 ]
    do
       echo $a
       a=`expr $a + 1`
    done
</code></pre><p>运行结果：</p>
<pre><code>0
1
2
3
4
</code></pre><hr>
<h5 id="shell-breakcontinue">Shell break和continue命令</h5>
<p>在循环过程中，有时候需要在未达到循环结束条件时强制跳出循环，像大多数编程语言一样，Shell也使用 break 和 continue 来跳出循环。
break命令
break命令允许跳出所有循环（终止执行后面的所有循环）。</p>
<p>下面的例子中，脚本进入死循环直至用户输入数字大于5。要跳出这个循环，返回到shell提示符下，就要使用break命令。</p>
<pre><code>    #!/bin/bash
    while :
    do
        echo -n &quot;Input a number between 1 to 5: &quot;
        read aNum
        case $aNum in
            1|2|3|4|5) echo &quot;Your number is $aNum!&quot;
            ;;
            *) echo &quot;You do not select a number between 1 to 5, game is over!&quot;
                break
            ;;
        esac
    done
</code></pre><p><code>在嵌套循环中，break 命令后面还可以跟一个整数，表示跳出第几层循环。</code>例如：</p>
<pre><code>    break n
</code></pre><p>表示跳出第 n 层循环。</p>
<p>下面是一个嵌套循环的例子，如果 var1 等于 2，并且 var2 等于 0，就跳出循环：</p>
<pre><code>    #!/bin/bash
    for var1 in 1 2 3
    do
       for var2 in 0 5
       do
          if [ $var1 -eq 2 -a $var2 -eq 0 ]
          then
             break 2
          else
             echo &quot;$var1 $var2&quot;
          fi
       done
    done
</code></pre><p>如上，break 2 表示直接跳出外层循环。运行结果：</p>
<pre><code>1 0
1 5
</code></pre><p>continue命令
continue命令与break命令类似，只有一点差别，它不会跳出所有循环，仅仅跳出当前循环。</p>
<p>对上面的例子进行修改：</p>
<pre><code>    #!/bin/bash
    while :
    do
        echo -n &quot;Input a number between 1 to 5: &quot;
        read aNum
        case $aNum in
            1|2|3|4|5) echo &quot;Your number is $aNum!&quot;
            ;;
            *) echo &quot;You do not select a number between 1 to 5!&quot;
                continue
                echo &quot;Game is over!&quot;
            ;;
        esac
    done
</code></pre><p>运行代码发现，当输入大于5的数字时，该例中的循环不会结束，语句</p>
<pre><code>    echo &quot;Game is over!&quot;
</code></pre><p>永远不会被执行。<br>
<code>同样，continue 后面也可以跟一个数字，表示跳出第几层循环。</code></p>
<hr>
<h5 id="shell12">Shell函数</h5>
<p>Shell函数：Shell函数返回值、删除函数、在终端调用函数<br>
函数可以让我们将一个复杂功能划分成若干模块，让程序结构更加清晰，代码重复利用率更高。像其他编程语言一样，Shell 也支持函数。Shell 函数必须先定义后使用。</p>
<p>Shell 函数的定义格式如下：</p>
<pre><code>function_name () {
    list of commands
    [ return value ]
}
</code></pre><p>如果你愿意，也可以在函数名前加上关键字 function：</p>
<pre><code>function function_name () {
    list of commands
    [ return value ]
}
</code></pre><p>函数返回值，可以显式增加return语句；如果不加，会将最后一条命令运行结果作为返回值。</p>
<p><code>Shell 函数返回值只能是整数</code>，一般用来表示函数执行成功与否，0表示成功，其他值表示失败。如果 return 其他数据，比如一个字符串，往往会得到错误提示：“numeric argument required”。</p>
<p>如果一定要让函数返回字符串，那么可以先定义一个变量，用来接收函数的计算结果，脚本在需要的时候访问这个变量来获得函数返回值。</p>
<p>先来看一个例子：</p>
<pre><code>    #!/bin/bash
    # Define your function here
    Hello () {
       echo &quot;Url is http://see.xidian.edu.cn/cpp/shell/&quot;
    }
    # Invoke your function
    Hello
</code></pre><p>运行结果：</p>
<pre><code>$./test.sh
Hello World
$
</code></pre><p>调用函数只需要给出函数名，不需要加括号。</p>
<p>再来看一个带有return语句的函数：</p>
<pre><code>    #!/bin/bash
    funWithReturn(){
        echo &quot;The function is to get the sum of two numbers...&quot;
        echo -n &quot;Input first number: &quot;
        read aNum
        echo -n &quot;Input another number: &quot;
        read anotherNum
        echo &quot;The two numbers are $aNum and $anotherNum !&quot;
        return $(($aNum+$anotherNum))
    }
    funWithReturn
    # Capture value returnd by last command
    ret=$?
    echo &quot;The sum of two numbers is $ret !&quot;
</code></pre><p>运行结果：</p>
<pre><code>The function is to get the sum of two numbers...
Input first number: 25
Input another number: 50
The two numbers are 25 and 50 !
The sum of two numbers is 75 !
</code></pre><p>函数返回值在调用该函数后通过 $? 来获得。</p>
<p>再来看一个函数嵌套的例子：</p>
<pre><code>    #!/bin/bash
    # Calling one function from another
    number_one () {
       echo &quot;Url_1 is http://see.xidian.edu.cn/cpp/shell/&quot;
       number_two
    }
    number_two () {
       echo &quot;Url_2 is http://see.xidian.edu.cn/cpp/u/xitong/&quot;
    }
    number_one
</code></pre><p>运行结果：</p>
<pre><code>Url_1 is http://see.xidian.edu.cn/cpp/shell/
Url_2 is http://see.xidian.edu.cn/cpp/u/xitong/
</code></pre><p>像删除变量一样，删除函数也可以使用 unset 命令，不过要加上 .f 选项，如下所示：</p>
<pre><code>    $unset .f function_name
</code></pre><p><code>如果你希望直接从终端调用函数，可以将函数定义在主目录下的 .profile 文件，这样每次登录后，在命令提示符后面输入函数名字就可以立即调用。</code></p>
<hr>
<h5 id="shell13">Shell函数参数</h5>
<p>在Shell中，调用函数时可以向其传递参数。在函数体内部，通过 $n 的形式来获取参数的值，例如，$1表示第一个参数，$2表示第二个参数&hellip;  
带参数的函数示例：</p>
<pre><code>#!/bin/bash
    funWithParam(){
        echo &quot;The value of the first parameter is $1 !&quot;
        echo &quot;The value of the second parameter is $2 !&quot;
        echo &quot;The value of the tenth parameter is $10 !&quot;
        echo &quot;The value of the tenth parameter is ${10} !&quot;
        echo &quot;The value of the eleventh parameter is ${11} !&quot;
        echo &quot;The amount of the parameters is $# !&quot;  # 参数个数
            echo &quot;The string of the parameters is $* !&quot;  # 传递给函数的所有参数
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73
</code></pre><p>运行脚本：</p>
<pre><code>The value of the first parameter is 1 !
The value of the second parameter is 2 !
The value of the tenth parameter is 10 !
The value of the tenth parameter is 34 !
The value of the eleventh parameter is 73 !
The amount of the parameters is 12 !
The string of the parameters is 1 2 3 4 5 6 7 8 9 34 73 !&quot;
</code></pre><p><code>注意，$10 不能获取第十个参数，获取第十个参数需要${10}。当n&gt;=10时，需要使用${n}来获取参数。</code></p>
<p>另外，还有几个特殊变量用来处理参数，前面已经提到：</p>
<table>
<thead>
<tr>
<th>特殊变量</th>
<th align="center">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>$#</td>
<td align="center">传递给函数的参数个数。</td>
</tr>
<tr>
<td>$*</td>
<td align="center">显示所有传递给函数的参数。</td>
</tr>
<tr>
<td>$@</td>
<td align="center">与$*相同，但是略有区别，请查看Shell特殊变量。</td>
</tr>
<tr>
<td>$?</td>
<td align="center">函数的返回值。</td>
</tr>
</tbody>
</table>
<hr>
<h5 id="shell14">Shell输入输出重定向</h5>
<p>Shell输入输出重定向：Shell Here Document，/dev/null文件<br>
Unix 命令默认从标准输入设备(stdin)获取输入，将结果输出到标准输出设备(stdout)显示。一般情况下，标准输入设备就是键盘，标准输出设备就是终端，即显示器。</p>
<h6 id="heading20">输出重定向</h6>
<p>命令的输出不仅可以是显示器，还可以很容易的转移向到文件，这被称为输出重定向。</p>
<p>命令输出重定向的语法为：</p>
<pre><code>    $ command &gt; file
</code></pre><p>这样，输出到显示器的内容就可以被重定向到文件。</p>
<p>例如，下面的命令在显示器上不会看到任何输出：</p>
<pre><code>    $ who &gt; users
</code></pre><p>打开 users 文件，可以看到下面的内容：</p>
<pre><code>$ cat users
oko         tty01   Sep 12 07:30
ai          tty15   Sep 12 13:32
ruth        tty21   Sep 12 10:10
pat         tty24   Sep 12 13:07
steve       tty25   Sep 12 13:03
$
</code></pre><p>输出重定向会覆盖文件内容，请看下面的例子：</p>
<pre><code>$ echo line 1 &gt; users
$ cat users
line 1
$
</code></pre><p>如果不希望文件内容被覆盖，可以使用 &raquo; 追加到文件末尾，例如：</p>
<pre><code>$ echo line 2 &gt;&gt; users
$ cat users
line 1
line 2
$
</code></pre><h6 id="heading21">输入重定向</h6>
<p>和输出重定向一样，Unix 命令也可以从文件获取输入，语法为：</p>
<pre><code>    command &lt; file
</code></pre><p>这样，本来需要从键盘获取输入的命令会转移到文件读取内容。</p>
<p>注意：输出重定向是大于号(&gt;)，输入重定向是小于号(&lt;)。</p>
<p>例如，计算 users 文件中的行数，可以使用下面的命令：</p>
<pre><code>$ wc -l users
2 users
$
</code></pre><p>也可以将输入重定向到 users 文件：</p>
<pre><code>$ wc -l &lt; users
2
$
</code></pre><p>注意：上面两个例子的结果不同：第一个例子，会输出文件名；第二个不会，因为它仅仅知道从标准输入读取内容。</p>
<h6 id="heading22">重定向深入讲解</h6>
<p>一般情况下，每个 Unix/Linux 命令运行时都会打开三个文件：</p>
<pre><code>-   标准输入文件(stdin)：stdin的文件描述符为0，Unix程序默认从stdin读取数据。
-   标准输出文件(stdout)：stdout 的文件描述符为1，Unix程序默认向stdout输出数据。
-   标准错误文件(stderr)：stderr的文件描述符为2，Unix程序会向stderr流中写入错误信息。
</code></pre>
<p>默认情况下，command &gt; file 将 stdout 重定向到 file，command &lt; file 将stdin 重定向到 file。</p>
<p>如果希望 stderr 重定向到 file，可以这样写：</p>
<pre><code>    $command 2 &gt; file
</code></pre><p>如果希望 stderr 追加到 file 文件末尾，可以这样写：</p>
<pre><code>    $command 2 &gt;&gt; file
</code></pre><p>2 表示标准错误文件(stderr)。</p>
<p>如果希望将 stdout 和 stderr 合并后重定向到 file，可以这样写：</p>
<pre><code>    $command &gt; file 2&gt;&amp;1
</code></pre><p>或</p>
<pre><code>    $command &gt;&gt; file 2&gt;&amp;1
</code></pre><p>如果希望对 stdin 和 stdout 都重定向，可以这样写：</p>
<pre><code>    $command &lt; file1 &gt;file2
</code></pre><p>command 命令将 stdin 重定向到 file1，将 stdout 重定向到 file2。</p>
<p>全部可用的重定向命令列表</p>
<table>
<thead>
<tr>
<th>命令</th>
<th align="center">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>command &gt; file</td>
<td align="center">将输出重定向到 file。</td>
</tr>
<tr>
<td>command &lt; file</td>
<td align="center">将输入重定向到 file。</td>
</tr>
<tr>
<td>command &raquo; file</td>
<td align="center">将输出以追加的方式重定向到 file。</td>
</tr>
<tr>
<td>n &gt; file</td>
<td align="center">将文件描述符为 n 的文件重定向到 file。</td>
</tr>
<tr>
<td>n &raquo; file</td>
<td align="center">将文件描述符为 n 的文件以追加的方式重定向到 file。</td>
</tr>
<tr>
<td>n &gt;&amp; m</td>
<td align="center">将输出文件 m 和 n 合并。</td>
</tr>
<tr>
<td>n &lt;&amp; m</td>
<td align="center">将输入文件 m 和 n 合并。</td>
</tr>
<tr>
<td>&laquo; tag</td>
<td align="center">将开始标记 tag 和结束标记 tag 之间的内容作为输入。</td>
</tr>
<tr>
<td>Here Document</td>
<td></td>
</tr>
<tr>
<td>Here Document 目前没有统一的翻译，这里暂译为”嵌入文档“。Here Document 是 Shell 中的一种特殊的重定向方式，它的基本的形式如下：</td>
<td></td>
</tr>
</tbody>
</table>
<pre><code>    command &lt;&lt; delimiter
        document
    delimiter
</code></pre><p>它的作用是将两个 delimiter 之间的内容(document) 作为输入传递给 command。</p>
<p>注意：</p>
<pre><code>结尾的delimiter 一定要顶格写，前面不能有任何字符，后面也不能有任何字符，包括空格和 tab 缩进。
开始的delimiter前后的空格会被忽略掉。
</code></pre>
<p>下面的例子，通过 wc -l 命令计算 document 的行数：</p>
<pre><code>$wc -l &lt;&lt; EOF
    This is a simple lookup program
    for good (and bad) restaurants
    in Cape Town.
EOF
3
$
</code></pre><p>也可以 将 Here Document 用在脚本中，例如：</p>
<pre><code>    #!/bin/bash
    cat &lt;&lt; EOF
    This is a simple lookup program
    for good (and bad) restaurants
    in Cape Town.
    EOF
</code></pre><p>运行结果：</p>
<pre><code>This is a simple lookup program
for good (and bad) restaurants
in Cape Town.
</code></pre><p>下面的脚本通过 vi 编辑器将 document 保存到 test.txt 文件：</p>
<pre><code>    #!/bin/sh
    filename=test.txt
    vi $filename &lt;&lt;EndOfCommands
    i
    This file was created automatically from
    a shell script
    ^[
    ZZ
    EndOfCommands
</code></pre><p>运行脚本：</p>
<pre><code>$ sh test.sh
Vim: Warning: Input is not from a terminal
$
</code></pre><p>打开 test.txt，可以看到下面的内容：</p>
<pre><code>$ cat test.txt
This file was created automatically from
a shell script
$
</code></pre><h6 id="devnull-">/dev/null 文件</h6>
<p>如果希望执行某个命令，但又不希望在屏幕上显示输出结果，那么可以将输出重定向到 /dev/null：</p>
<pre><code>    $ command &gt; /dev/null
</code></pre><p>/dev/null 是一个特殊的文件，写入到它的内容都会被丢弃；如果尝试从该文件读取内容，那么什么也读不到。但是 /dev/null 文件非常有用，将命令的输出重定向到它，会起到”禁止输出“的效果。</p>
<p>如果希望屏蔽 stdout 和 stderr，可以这样写：</p>
<hr>
<h5 id="shell15">Shell文件包含</h5>
<p>像其他语言一样，Shell 也可以包含外部脚本，将外部脚本的内容合并到当前脚本。</p>
<p>Shell 中包含脚本可以使用：</p>
<pre><code>    . filename
</code></pre><p>或</p>
<pre><code>    source filename
</code></pre><p>两种方式的效果相同，简单起见，一般使用点号(.)，但是注意点号(.)和文件名中间有一空格。</p>
<p>例如，创建两个脚本，一个是被调用脚本 subscript.sh，内容如下：</p>
<pre><code>    url=&quot;http://see.xidian.edu.cn/cpp/view/2738.html&quot;
</code></pre><p>一个是主文件 main.sh，内容如下：</p>
<pre><code>    #!/bin/bash
    . ./subscript.sh
    echo $url
</code></pre><p>执行脚本：</p>
<pre><code>$chomd +x main.sh
./main.sh
http://see.xidian.edu.cn/cpp/view/2738.html
$
</code></pre><p>注意：被包含脚本不需要有执行权限。</p>
<hr>

</div>


  
</article>
      <footer id="main-footer" class="container main_footer">
  

  <div class="container nav foot no-print">
  
<a href="https://lvzongcheng.gitee.io/license">license</a>


  <a class="toplink" href="#">back to top</a>

</div>

  <div class="container credits">
  
<div class="container footline">
  
  code with <!-- raw HTML omitted --><!-- raw HTML omitted -->


</div>


  
<div class="container copyright">
  
  (c) 2015 yourname.


</div>


</div>

</footer>

    </main>
    
<script type="text/javascript">
  (function() {
    
    
    if (window.location.hostname == "localhost")
      return;
    var dsq = document.createElement('script'); dsq.async = true; dsq.type = 'text/javascript';
    dsq.src = '//your_disqus_shortname.disqus.com/count.js';
    (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
  })();
</script>



<script src="/js/highlight.pack.js"></script>
<script>hljs.initHighlightingOnLoad();</script>



    
  </body>
</html>

